package org.yagnus.langutils.tuples;

/**
 *
 * @author hc.busy
 *
 * typed, ordered two tupples used for returning two things from a function
 *
 * @param <TA> any class
 * @param <TB> any class
 */
public class TwoTuple<TA, TB> {

    public final TA a;
    public final TB b;

    public TwoTuple(TA a, TB b) {
        this.a = a;
        this.b = b;
    }

    public final TA getA() {
        return a;
    }

    public final TB getB() {
        return b;
    }

    /**
     *
     * convenience function for making a two tupple
     *
     * @param <TC>
     * @param <TD>
     * @param c
     * @param d
     * @return
     */
    public static <TC, TD> TwoTuple<TC, TD> make(TC c, TD d) {
        return new TwoTuple<TC, TD>(c, d);
    }

    /**
     * short hand for making a two tupple.
     * 
     * @param <TC>
     * @param <TD>
     * @param c
     * @param d
     * @return
     */
    public static <TC, TD> TwoTuple<TC, TD> c(TC c, TD d) {
        return make(c, d);
    }

    @Override
    public boolean equals(Object obj) {

        if (obj == null) {
            return false; //since this object wasn't null
        }
        if (obj instanceof TwoTuple) {
            try {

                TwoTuple<TA, TB> obj2 = (TwoTuple<TA, TB>) obj;

                boolean an = (a == null),
                        oan = (obj2.a == null);
                if (!an && !oan) {
                    if (!a.equals(obj2.a)) {
                        return false;
                    }
                } else if (an ^ oan) {
                    return false; //when nullness is different
                }

                //get here only if a==o.a via nullness or compareTo==0
                boolean bn = (b == null),
                        obn = (obj2.b == null);
                if (!bn && !obn) {
                    return b.equals(obj2.b);
                } else {
                    return (bn && obn); //if at least one of the b's is null, then equality only happens when both are null
                }

            } catch (ClassCastException e) {
                return false;
            }
        }

        return false;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash =
                53 * hash + (this.a != null ? this.a.hashCode() : 0);
        hash =
                53 * hash + (this.b != null ? this.b.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return "(" + a + ", " + b + ")";
    }
}
